<template>
  <div
    id="hlsPlayer-container"
    class="hlsPlayer-container"
    @mouseenter="controlsShow = true"
    @mouseleave="mouseleave"
    @mousemove="controlsShow = true"
  >
    <!-- 视频 -->
    <video
      id="videoPlayer"
      preload="auto"
      @click="clickVideo"
      @dblclick="dblClickVideo"
      @ended="videoEnd"
      @play="videoStatus = true"
      @pause="videoStatus = false"
    ></video>
    <!-- 控制 -->
    <Transition name="expand" appear>
      <div id="controls" class="controls" v-if="controlsShow">
        <!-- 播放按钮 -->
        <el-icon color="#ffffff" v-if="!videoStatus" @click="clickVideo">
          <svg
            t="1742302047183"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="5746"
            width="256"
            height="256"
          >
            <path d="M891.161 512l-749.992 450v-900l749.992 450z" p-id="5747"></path>
          </svg>
        </el-icon>
        <!-- 暂停按钮 -->
        <el-icon color="#ffffff" v-if="videoStatus" @click="clickVideo">
          <svg
            t="1742304512798"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="2474"
            width="256"
            height="256"
          >
            <path d="M209.417 62h150.008v900h-150.008v-900z" p-id="2475"></path>
            <path d="M659.417 62h149.985v900h-149.985v-900z" p-id="2476"></path>
          </svg>
        </el-icon>
        {{ secondToMMss(currentTime) }} / {{ secondToMMss(videodDuration) }}
        <br />
        <!-- 进度条 -->
        <el-slider
          class="sidebarProgress"
          v-model="currentTime"
          :format-tooltip="secondToMMss"
          @change="currentTimeChange"
          @input="currentTimeInput"
          @click="sliderClick"
          :min="0"
          :max="videodDuration"
          style="width: 60%"
        />
        <!-- 音量控制 -->
        <el-dropdown placement="top" popper-class="levelClass v" :teleported="false">
          <span class="el-dropdown-link" @click="toMute">
            <!-- 静音图标 -->
            <el-icon color="#ffffff" v-if="muted">
              <svg
                t="1742305979834"
                class="icon"
                viewBox="0 0 1025 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="2364"
                width="256"
                height="256"
              >
                <path
                  d="M652.569422 94.472586a25.86878 25.86878 0 0 1 17.409787-6.491785 26.262221 26.262221 0 0 1 26.163861 26.262221V529.22546l78.688303 78.688303V114.243022a104.950524 104.950524 0 0 0-173.99951-78.688303L388.176725 221.259114l55.770334 55.770335zM1012.470048 956.798025l-944.259635-944.259634-1.967207-1.967208a39.344151 39.344151 0 1 0-53.704767 57.639182l189.73717 189.63881A157.376606 157.376606 0 0 0 92.800508 407.553671v219.146924a157.376606 157.376606 0 0 0 157.376606 148.13073H355.127637l245.900947 214.917427 6.196704 5.11474a104.950524 104.950524 0 0 0 167.802806-84.098124v-80.360429l181.9667 182.065061a39.344151 39.344151 0 0 0 55.671974-55.671975z m-316.326978-46.032657v4.426217a26.557302 26.557302 0 0 1-6.098343 12.88521 26.163861 26.163861 0 0 1-36.983503 2.459009l-245.900946-214.917427-6.393425-5.11474a78.688303 78.688303 0 0 0-45.442495-14.360615H242.701725a78.688303 78.688303 0 0 1-71.212914-78.688303v-217.376436a78.688303 78.688303 0 0 1 78.688303-71.212915h23.114689l422.949627 422.949628z"
                  p-id="2365"
                ></path>
              </svg>
            </el-icon>
            <!-- 喇叭图标 -->
            <el-icon color="#ffffff" v-if="!muted">
              <svg
                t="1742306165254"
                class="icon"
                viewBox="0 0 1024 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="6895"
                width="256"
                height="256"
              >
                <path
                  d="M543.46816641 12.67981694h-2.9066981c-11.75317061 0-23.50634119 2.90669808-35.25951178 11.75317057-173.26448266 149.75814146-264.25677117 228.99725934-273.1032436 237.84373188H88.38034583c-17.56656678 0-32.35281366 5.8133962-44.1059843 17.56656681-11.75317061 11.75317061-17.56656678 26.4130393-17.56656678 44.10598429v381.66209891c0 17.56656678 5.8133962 32.35281366 17.56656678 43.97960609 11.75317061 11.75317061 26.4130393 17.56656678 44.1059843 17.56656681h140.91166899c2.90669808 2.90669808 29.3197374 26.4130393 73.42572166 64.57924916 44.10598425 38.16620989 90.9922885 76.33241979 132.19157465 111.59193161 44.10598425 35.25951178 64.57924916 55.73277668 67.48594728 55.7327767 11.75317061 8.84647248 23.50634119 11.75317061 35.25951183 11.75317058h2.90669807c23.50634119-2.90669808 38.16620989-17.56656678 44.10598431-44.10598431V56.65942303c-3.03307629-26.4130393-17.69294499-41.07290797-41.19928621-43.97960609zM889.99713178 206.41756452c-11.75317061-14.6598687-29.3197374-14.6598687-44.10598433-2.90669811-11.75317061 11.75317061-11.75317061 26.4130393-2.9066981 38.16620989 58.76585296 73.42572169 93.89898659 167.32470823 93.89898661 270.19654555 0 102.74545907-35.25951178 196.77082385-93.89898661 270.19654552-8.84647248 11.75317061-8.84647248 26.4130393 2.9066981 38.16620988s32.35281366 11.75317061 44.10598433-2.90669811c67.4859473-85.17889229 105.65215719-190.83104943 105.65215719-308.36275543s-41.07290797-217.37046694-105.65215719-302.54935919zM719.63934721 329.76266669c-11.75317061 11.75317061-11.75317061 26.4130393-5.81339626 35.25951176 29.3197374 41.07290797 44.10598425 93.89898659 44.10598434 146.8514434 0 55.73277668-17.56656678 105.65215719-44.10598434 146.85144334-8.84647248 11.75317061-5.8133962 26.4130393 2.90669817 35.25951176 11.75317061 11.75317061 32.35281366 11.75317061 44.10598422-2.90669809 35.25951178-52.82607858 55.73277668-114.49862967 55.73277671-179.07787886 0-67.4859473-20.59964306-129.15849838-55.73277671-179.07787886-5.93977442-14.91262503-26.53941746-17.81932318-41.19928613-3.15945445z"
                  fill=""
                  p-id="6896"
                ></path>
              </svg>
            </el-icon>
          </span>
          <!-- 音量条 -->
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item>
                <el-slider
                  class="volume"
                  v-model="volume"
                  vertical
                  height="100px"
                  :min="0"
                  :max="100"
                  @change="volumeChange"
                  @input="volumeInput"
                  tooltip-class="progressTips"
                />
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
        <!-- 清晰度控制 -->
        <el-dropdown
          placement="top"
          @command="changeQuality"
          popper-class="levelClass"
          :teleported="false"
        >
          <span class="el-dropdown-link"> {{ qualityName }} </span>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item
                v-for="(level, index) in qualityLevels"
                :key="index"
                :value="index"
                :command="level"
              >
                {{ level.resolution }}
              </el-dropdown-item>
              <el-dropdown-item :command="{ resolution: '自动', index: -1 }">
                自动
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
        <!-- 倍速控制 -->
        <el-dropdown
          placement="top"
          @command="changeSpeed"
          popper-class="levelClass"
          :teleported="false"
        >
          <span class="el-dropdown-link"> {{ videoSpeed + 'x' }} </span>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item
                v-for="(item, index) in speedArr"
                :key="index"
                :value="index"
                :command="item"
              >
                {{ item }}x
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
        <!-- 全屏按钮 -->
        <el-icon color="#ffffff" @click="dblClickVideo">
          <svg
            t="1742305101863"
            class="icon"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="3446"
            width="256"
            height="256"
          >
            <path
              d="M181 357.5V181.2h176.4c14.3 0 25.9-11.6 25.9-25.9v-31.1c0-14.3-11.6-25.9-25.9-25.9H118c-11 0-20 9-20 20v239.4c0 14.3 11.6 25.9 25.9 25.9H155c14.4-0.1 26-11.7 26-26.1zM668.6 181.2H845v176.4c0 14.3 11.6 25.9 25.9 25.9H902c14.3 0 25.9-11.6 25.9-25.9V118.2c0-11-9-20-20-20H668.6c-14.3 0-25.9 11.6-25.9 25.9v31.1c0 14.3 11.6 26 25.9 26zM357.4 845.2H181V668.8c0-14.3-11.6-25.9-25.9-25.9H124c-14.3 0-25.9 11.6-25.9 25.9v239.4c0 11 9 20 20 20h239.4c14.3 0 25.9-11.6 25.9-25.9v-31.1c-0.1-14.4-11.7-26-26-26zM845 668.8v176.4H668.6c-14.3 0-25.9 11.6-25.9 25.9v31.1c0 14.3 11.6 25.9 25.9 25.9H908c11 0 20-9 20-20V668.8c0-14.3-11.6-25.9-25.9-25.9H871c-14.4 0-26 11.6-26 25.9z"
              p-id="3447"
            ></path>
          </svg>
        </el-icon>
      </div>
    </Transition>
  </div>
</template>

<script lang="ts" setup>
import { useVideoStore } from '@/stores/videoStore'
import Hls from 'hls.js'
import Cookies from 'js-cookie'
import { secondToMMss } from '@/utils/format'

const videoStore = useVideoStore()

const props = defineProps({
  masterUrl: {
    type: String,
    required: true
  }
})

let timeoutId: number
const controlsShow = ref(true)

// 监听鼠标移动
const resetTimer = () => {
  if (timeoutId) {
    clearTimeout(timeoutId)
  }
  timeoutId = setTimeout(() => {
    controlsShow.value = false // 2秒后隐藏
  }, 2000)
}

const masterUrlRef = computed(() => props.masterUrl)

watch(masterUrlRef, () => {
  hlsDestroy()
  videoInit()
  hlsInit()
  videoPlayer.play()
})

let hlsPlayerContainer: HTMLDivElement
let videoPlayer: HTMLVideoElement

// 视频播放状态
const videoStatus = ref(false)
// 播放的时长
const currentTime = ref(0)
// 已缓存时长
const BufferedTime = ref(0)
// 视频总时长
const videodDuration = ref(0)
// 存储各个分辨率信息
const qualityLevels = ref<{ resolution: string; index: number }[]>([])
// -1 表示自动
const selectedQuality = ref(-1)
// 分辨率名称
const qualityName = ref('自动')
// 播放速度
const videoSpeed = ref(1)
const speedArr = ref([3, 2.5, 2, 1.5, 1, 0.5])

// 音量
const volume = ref(100)
const lastVolume = ref(10)
const muted = ref(false)

// 样式
const theme = ref({
  progress: '90%'
})

let hls: Hls | null

onMounted(() => {
  window.addEventListener('mousemove', resetTimer)
  resetTimer() // 触发初始倒计时

  hlsPlayerContainer = document.getElementById('hlsPlayer-container')! as HTMLDivElement
  videoPlayer = document.getElementById('videoPlayer')! as HTMLVideoElement
  muted.value = videoStore.muted ?? false
  lastVolume.value = videoStore.lastVolume ?? 50
  volume.value = videoStore.volume ?? 100
  videoPlayer.volume = volume.value / 100
  hlsDestroy()
  hlsInit()

  // 监听加载
  videoPlayer.addEventListener('loadedmetadata', function () {
    videodDuration.value = videoPlayer.duration
    videoPlayer.volume = volume.value / 100
  })
  // 监听播放进度
  videoPlayer.addEventListener('timeupdate', function () {
    currentTime.value = videoPlayer.currentTime
  })
  // 监听缓存进度
  videoPlayer.addEventListener('progress', function () {
    if (videoPlayer && videoPlayer.buffered && videoPlayer.buffered.length > 0) {
      const lastBufferedTime = videoPlayer.buffered.end(videoPlayer.buffered.length - 1)
      BufferedTime.value = lastBufferedTime

      theme.value.progress = (BufferedTime.value / videodDuration.value) * 100 + '%'
    }
  })
  // 监听音量
  videoPlayer.addEventListener('volumechange', () => {
    // 更新当前音量
    muted.value = videoPlayer.volume == 0
    videoStore.muted = muted.value
  })
})

function videoInit() {
  currentTime.value = 0
  BufferedTime.value = 0
  videodDuration.value = 0
  qualityLevels.value = []
  selectedQuality.value = -1
  qualityName.value = '自动'
  videoSpeed.value = 1
  videoPlayer.playbackRate = 1
}

// hls init
function hlsInit() {
  // 加载视频
  if (Hls.isSupported() || navigator.userAgent.includes('Safari')) {
    hls = new Hls({
      xhrSetup: function (xhr) {
        xhr.setRequestHeader('Authorization', Cookies.get('quicklyToken') ?? '')
      }
    })

    hls.loadSource(masterUrlRef.value)
    hls.attachMedia(videoPlayer)
    hls.on(Hls.Events.MANIFEST_PARSED, () => {
      // 提取各个质量层级信息
      qualityLevels.value = hls!.levels.map((level, index) => {
        let resolution = ''
        // 如果 hls.js 已经提供 height，就直接用
        if (level.height) {
          resolution = level.height + 'p'
        } else if (level.url && level.url.length > 0) {
          // 如果没有 height，从 TS 文件名中解析 (例如 stream_360_004.ts)
          const match = level.url[0].split('_')
          if (match && match[1]) {
            resolution = match[1].replace('.m3u8', '') + 'P'
          } else {
            resolution = '未知'
          }
        } else {
          resolution = '未知'
        }
        return {
          resolution,
          index // 这里的 index 与 hlsInstance.levels 中的顺序对应
        }
      })
      selectedQuality.value = -1 // 默认自动模式
      qualityLevels.value.sort((a, b) => {
        return parseInt(b.resolution.replace('P', '')) - parseInt(a.resolution.replace('p', ''))
      })
    })
  } else {
    // 兜底
    videoPlayer.src = masterUrlRef.value
  }
}

function hlsDestroy() {
  if (hls) {
    hls.destroy()
    hls = null // 避免引用残留
  }
}

// 单击视频
function clickVideo() {
  if (videoPlayer.paused) {
    videoPlayer.play()
  } else {
    videoPlayer.pause()
  }
}

// 双击视频
function dblClickVideo() {
  if (!document.fullscreenElement) {
    // 如果当前没有全屏元素，则让 hlsPlayerContainer 进入全屏
    hlsPlayerContainer.requestFullscreen().catch((err) => {
      console.error('进入全屏失败:', err)
    })
  } else {
    // 如果当前有全屏元素，则退出全屏
    document.exitFullscreen().catch((err) => {
      console.error('退出全屏失败:', err)
    })
  }
}

// 进度条
function currentTimeChange(e: number) {
  videoPlayer.currentTime = e
  if (videoPlayer.paused) {
    videoPlayer.play()
  }
}
function currentTimeInput(e: number) {
  if (!videoPlayer.paused) {
    videoPlayer.pause()
  }
  videoPlayer.currentTime = e
}
function sliderClick() {
  if (!videoPlayer.paused) {
    videoPlayer.pause()
  }
}

// 音量条
function volumeChange(val: number) {
  videoStore.volume = val
  videoPlayer.volume = val / 100
}
function volumeInput(val: number) {
  videoStore.volume = val
  videoPlayer.volume = val / 100
}

// 分辨率改变
function changeQuality(level: { resolution: string; index: number }) {
  qualityName.value = level.resolution
  selectedQuality.value = level.index

  if (!videoPlayer.paused) {
    videoPlayer.pause()
  }
  if (hls) {
    hls.currentLevel = selectedQuality.value // 手动指定
  }
  if (videoPlayer.paused) {
    videoPlayer.play()
  }
}

// 播放速度改变
function changeSpeed(speed: number) {
  videoSpeed.value = speed
  videoPlayer.playbackRate = speed
}

let timeoutId2: number
// 鼠标移出
function mouseleave() {
  if (timeoutId2) {
    clearTimeout(timeoutId2)
  }
  timeoutId2 = setTimeout(() => {
    controlsShow.value = false // 2秒后隐藏
  }, 2000)
}

function toMute() {
  if (muted.value) {
    muted.value = false
    volume.value = lastVolume.value
  } else {
    muted.value = true
    lastVolume.value = volume.value
    videoStore.lastVolume = volume.value
    volume.value = 0
  }
  videoStore.volume = volume.value
  videoStore.muted = muted.value
  videoPlayer.volume = volume.value / 100
}

// 视频播放结束事件
const emit = defineEmits(['videoEnded'])
// 监听视频播放结束
const videoEnd = () => {
  // 通知父组件
  emit('videoEnded')
}
</script>

<style lang="scss" scoped>
.hlsPlayer-container {
  width: 100%;
  aspect-ratio: 16 / 9;
  background-color: rgba(255, 255, 255, 0);
  position: relative;
  display: flex;
  justify-content: center;
  align-self: center;
  video {
    width: 100%;
    margin: 0;
    padding: 0;
  }
  .controls {
    width: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    margin: 0;
    padding: 0;
    height: 60px;
    position: absolute;
    color: white;
    bottom: 0px;
    display: flex;
    align-items: center;
    justify-content: space-around;
  }
}

/* 进度条 */
:deep(.el-dropdown) {
  color: white;
}

:deep(.el-slider__bar) {
  border-radius: 0;
}

:deep(.el-slider__runway) {
  border-radius: 0;
  &:before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: v-bind('theme.progress');
    height: 100%;
    background: rgb(180, 183, 183);
  }
}
.el-slider.sidebarProgress {
  width: 5%;
  transition: width 0.2s ease-in-out;
  .el-slider__runway {
    width: 4px;
  }
  .el-slider__bar {
    width: 4px;
  }
  &:hover {
    width: 10%;
  }
  :deep(.el-slider__button) {
    border: none;
    border-radius: 1px;
    width: 8px;
    height: 11px;
  }

  :golbal(.progressTips) {
    * {
      color: green;
    }
  }
}
.el-slider.volume {
  width: 5%;
  transition: width 0.2s ease-in-out;
  .el-slider__runway {
    width: 4px;
  }
  .el-slider__bar {
    width: 4px;
  }
  &:hover {
    width: 10%;
  }
  :deep(.el-slider__button) {
    border: none;
    border-radius: 1px;
    width: 8px;
    height: 11px;
  }

  :golbal(.progressTips) {
    * {
      color: green;
    }
  }
}
</style>
<style>
.levelClass {
  --el-bg-color-overlay: rgba(0, 0, 0, 0.5);
  --el-border-color-light: rgba(0, 0, 0, 0);
  --el-dropdown-menuItem-hover-fill: #333;
  --el-dropdown-menuItem-hover-color: white;
  background-color: rgba(0, 0, 0, 0);
  .el-dropdown__popper.el-popper {
    border: none;
    box-shadow: none;
  }
  :deep(.el-dropdown-menu) {
    background-color: rgba(0, 0, 0, 0);
  }
  .el-dropdown-menu__item {
    color: white;
  }
}
.levelClass.v {
  --el-dropdown-menuItem-hover-fill: rgba(0, 0, 0, 0);
}

/* 进入动画 */
.expand-enter-active,
.expand-leave-active {
  transition:
    max-height 1s ease-in-out,
    opacity 1s ease-in-out;
}

/* 进入前 */
.expand-enter-from {
  max-height: 0;
  opacity: 0;
}

/* 进入后 */
.expand-enter-to {
  max-height: 200px; /* 这里的 200px 需要根据实际内容调整 */
  opacity: 1;
}

/* 离开前 */
.expand-leave-from {
  max-height: 200px;
  opacity: 1;
}

/* 离开后 */
.expand-leave-to {
  max-height: 0;
  opacity: 0;
}
</style>
